﻿#ifdef LINUX

#include "Async/Process.h"
#include "Output/Console.h"
#include "Path/Paths.h"
#include "Async/PackagedTask.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>

class CProcessPlatformData
{
public:
    //进程句柄
    pid_t ProcessId=0;
    pid_t ThreadId=0;

    //标准输出管道
    int StdoutRead=0;
    int StdoutWrite=0;

    //标准错误管道
    int StderrRead=0;
    int StderrWrite=0;
};

void RProcess::CreatePlatformData()
{
    PlatformData=new CProcessPlatformData();
}

void RProcess::DestroyPlatformData()
{
    delete PlatformData;
    PlatformData=nullptr;
}

void RProcess::Start(
    const CString &Program
    , const TVector<CString> &Arguments
    ,bool bReciveOutput
    ,bool bReciveError
    )
{
    assert(State==EProcessState::NotRunning);
    State=EProcessState::Starting;

    //创建管道以读取子进程的输出
    //use Linux api
    int fd[2];
    if(pipe(fd)<0)
    {
        WH::PrintLine(U"启动进程失败: 创建通信管道失败");
        return;
    }

    //创建错误管道
    int fdErr[2];
    if(pipe(fdErr)<0)
    {
        WH::PrintLine(U"启动进程失败: 创建通信管道失败");
        return;
    }

    //创建子进程
    pid_t pid=fork();
    if(pid<0)
    {
        WH::PrintLine(U"启动进程失败: 创建子进程失败");
        return;
    }

    if(pid==0)
    {
        //子进程
        //关闭读取管道
        close(fd[0]);
        close(fdErr[0]);

        //重定向标准输出
        dup2(fd[1],STDOUT_FILENO);
        close(fd[1]);

        //重定向标准错误
        dup2(fdErr[1],STDERR_FILENO);
        close(fdErr[1]);

        //执行程序
        char** argv=new char*[Arguments.Num()+2];
        auto ProgramUTF8=Program.ToUtf8();
        argv[0]=( char*)ProgramUTF8.Data();

        TVector<TVector<char8_t>> ArgumentsUTF8;
        for(const auto& Arg : Arguments)
        {
            ArgumentsUTF8.Add(Arg.ToUtf8());
        }

        for(int i=0;i<ArgumentsUTF8.Num();++i)
        {
            argv[i+1]=(char*)ArgumentsUTF8[i].Data();
        }
        argv[Arguments.Num()+1]=nullptr;

        execvp(argv[0],argv);

        //如果execvp失败
        WH::PrintLine(U"启动进程失败: 执行程序失败");
        exit(1);
    }
    
    
    //父进程
    // //关闭写入管道
    // close(fd[1]);
    // close(fdErr[1]);

    ((CProcessPlatformData*)PlatformData)->ProcessId=pid;
    ((CProcessPlatformData*)PlatformData)->ThreadId=pid;

    //保存管道
    ((CProcessPlatformData*)PlatformData)->StdoutRead=fd[0];
    ((CProcessPlatformData*)PlatformData)->StderrRead=fdErr[0];

    ((CProcessPlatformData*)PlatformData)->StdoutWrite=fd[1];
    ((CProcessPlatformData*)PlatformData)->StderrWrite=fdErr[1];

    State=EProcessState::Running;

    if(bReciveOutput)
    {
        StartReciveOutputTask();
    }

    if(bReciveError)
    {
        StartReciveErrorTask();
    }

    StartDetecteTask();
    

}

void RProcess::Stop()
{
    //关闭进程

    if(State==EProcessState::Running)
    {
        kill(((CProcessPlatformData*)PlatformData)->ProcessId,SIGKILL);
        ((CProcessPlatformData*)PlatformData)->ProcessId=0;
        ((CProcessPlatformData*)PlatformData)->ThreadId=0;
        State=EProcessState::NotRunning;
    }
}

void RProcess::WaitForFinished(int64_t Ms)
{
    if(State==EProcessState::Running)
    {
        if(Ms<0)
        {
            //无限等待
            int status;
            waitpid(((CProcessPlatformData*)PlatformData)->ProcessId,&status,0);
        }
        else
        {
            //有限等待
            auto StartTime=std::chrono::steady_clock::now();
            for(;;)
            {
                int status;
                waitpid(((CProcessPlatformData*)PlatformData)->ProcessId,&status,WNOHANG);
                if(status!=0)
                {
                    break;
                }

                auto EndTime=std::chrono::steady_clock::now();
                auto Duration=std::chrono::duration_cast<std::chrono::milliseconds>(EndTime-StartTime);
                if(Duration.count()>=Ms)
                {
                    break;
                }
            }

            int status;
            waitpid(((CProcessPlatformData*)PlatformData)->ProcessId,&status,WNOHANG);

            //等待指定时间
            usleep(Ms*1000);

            //检测是否结束
            waitpid(((CProcessPlatformData*)PlatformData)->ProcessId,&status,WNOHANG);


        }

    }
}




void RProcess::StartReciveOutputTask()
{

    //启动一个异步任务，读取子进程的输出
    auto OutRead=((CProcessPlatformData*)PlatformData)->StdoutRead;
    std::shared_ptr<CPackagedTask<TVector<uint8_t>>> 
            OutputReadTask = WH::CreateAsyncTask<TVector<uint8_t>>(
                [OutRead](bool& )mutable ->TVector<uint8_t>
    {
        //从管道中读取子进程的输出
        uint8_t Buffer[4096];
        ssize_t BytesRead=read(OutRead, Buffer, sizeof(Buffer));
        if (BytesRead <= 0)
        {
            //什么都没有读取到
            return TVector<uint8_t>();
        }
        TVector<uint8_t> Output(Buffer, BytesRead);
        return Output;
    });

    RProcessWeakPtr WeakThis=this;
    OutputReadTask->ThenInMainThread<void>(
        [OutputReadTask,WeakThis](bool& bSucceed)mutable ->void
    {
        if(!WeakThis)
        {
            //进程已经被销毁，不需要再输出
            close(((CProcessPlatformData*)WeakThis->PlatformData)->StdoutRead);
            close(((CProcessPlatformData*)WeakThis->PlatformData)->StdoutWrite);

            ((CProcessPlatformData*)WeakThis->PlatformData)->StdoutRead=0;
            ((CProcessPlatformData*)WeakThis->PlatformData)->StdoutWrite=0;
            return;
        }

        WeakThis->NotifyStandardOutput(
            std::move(OutputReadTask->Task->GetResult())
        );
        
        //继续读取
        WeakThis->StartReciveOutputTask();
    });
    OutputReadTask->Start();
}

void RProcess::StartReciveErrorTask()
{
    //启动一个异步任务，读取子进程的输出
    auto OutRead=((CProcessPlatformData*)PlatformData)->StderrRead;
    std::shared_ptr<CPackagedTask<TVector<uint8_t>>> 
            OutputReadTask = WH::CreateAsyncTask<TVector<uint8_t>>(
                [OutRead](bool& )mutable ->TVector<uint8_t>
    {
        //从管道中读取子进程的输出
        uint8_t Buffer[4096];
        ssize_t BytesRead=read(OutRead, Buffer, sizeof(Buffer));
        if (BytesRead <= 0)
        {
            //什么都没有读取到
            return TVector<uint8_t>();
        }
        TVector<uint8_t> Output(Buffer, BytesRead);
        return Output;
    });

    RProcessWeakPtr WeakThis=this;
    OutputReadTask->ThenInMainThread<void>(
        [OutputReadTask,WeakThis](bool& bSucceed)mutable ->void
    {
        if(!WeakThis)
        {
            //进程已经被销毁，不需要再输出
            close(((CProcessPlatformData*)WeakThis->PlatformData)->StdoutRead);
            close(((CProcessPlatformData*)WeakThis->PlatformData)->StdoutWrite);

            ((CProcessPlatformData*)WeakThis->PlatformData)->StdoutRead=0;
            ((CProcessPlatformData*)WeakThis->PlatformData)->StdoutWrite=0;
            return;
        }

        WeakThis->NotifyStandardError(
            std::move(OutputReadTask->Task->GetResult())
        );
        
        //继续读取
        WeakThis->StartReciveErrorTask();
    });
    OutputReadTask->Start();
}

//异步检测进程是否结束
void RProcess::StartDetecteTask()
{
    auto _ProcessHandle=((CProcessPlatformData*)PlatformData)->ProcessId;

    std::shared_ptr<CPackagedTask<int>> 
            DetecteTask = WH::CreateAsyncTask<int>(
                [_ProcessHandle](bool& )mutable ->int
    {
        int status;
        waitpid((pid_t)_ProcessHandle,&status,WNOHANG);
        return status;
    });

    RProcessWeakPtr WeakThis=this;
    DetecteTask->ThenInMainThread<void>(
        [DetecteTask,WeakThis](bool& bSucceed)mutable ->void
    {
        if(!WeakThis)
        {
            //进程已经被销毁，不需要再检测
            return;
        }

        int status=DetecteTask->Task->GetResult();
        if(WIFEXITED(status))
        {
            //进程已经结束
            WeakThis->State=EProcessState::NotRunning;
            WeakThis->OnFinished.Broadcast(WEXITSTATUS(status),WEXITSTATUS(status)==0);

            return;
        }
        
        //继续检测
        WeakThis->StartDetecteTask();
    });


    DetecteTask->Start();
}

uint64_t RProcess::GetProcessId() const
{
    return ((CProcessPlatformData*)PlatformData)->ProcessId;
}

#endif